/*
 * -------------------------------------- 
 * FileName: 1_2.employee_manager.c 
 * Content:
 * 
 * Auther:  杨则瑞 
 * Encode:  utf-8 | CRLF                  
 * -------------------------------------- 
 */


#include<stdio.h>
#include<string.h>

#include<dual_list.h>


typedef struct employee_t
{

    char id[20];
    char name[256];
    char position[512];
 
} employee_t;

duList_t archivedEmployees;
duList_t employees;


const char motto[] = 
"====================================================================== \n"\
"      Task 1 :      Employee Manage System  (linked list):         \n"\
"---------------------------------------------------------------------- \n"\
"    welcome! You can use \"help\" command to get helper docs           \n"\
"                                                                       \n"\
"                                                                       \n"\
"====================================================================== \n";


const char helping[] = 
"======================================================================\n"
"add : \"add <id> <name> [discription]\"\n"
"   add a employee to currentEmployee list.\n"
"del : \"del <id> [-f(permanently)]\"\n"
"   del a employee from list, move it to Disinged employ list\n"
"       if \'-f\' is set, delete the entry permanently.\n"
"list : \"list [-a(show disigned)]\".\n"
"   list employee list.\n"
"show : \"show <id>\"\n"
"   print the name and discription of the entry with same id\n"
"quit : \"quit\".\n"
"   quit the programme\n"
"help : \"help\".\n"
"   print this page.\n"
"======================================================================\n";


static void cmd_list(const char *args);
static void cmd_quit(const char *);
static void cmd_add(const char * args);
static void cmd_query(const char * args);
static void cmd_help(const char * args);
static void cmd_delete(const char * args);



void init()
{
    printf("initing...\n");

    duList_error_t app_erros = duList_OK;
    duList_init(&archivedEmployees, sizeof(employee_t), &app_erros);
    duList_init(&employees, sizeof(employee_t), &app_erros);

    if(app_erros != duList_OK)
    {
        printf("Encounter errors in initing database.\n");
        return;
    }

    printf(motto);
}


int running = 0;

int main(int argc, char * argv[])
{
    char cmd_buffer[1024];


    init();

    struct cmd_t {
        char command_name[20];
        void (*command)  (const char *);
    };

    struct cmd_t cmds[] = {
       {"list", cmd_list},
       {"add",  cmd_add},
       {"quit", cmd_quit},
       {"del", cmd_delete},
       {"show", cmd_query},
       {"help", cmd_help}
    };

    running = 1;
    while(running)
    {
        printf("\r>");
        fflush(stdout);
        fgets(cmd_buffer,1000,stdin);

        char ins[20];
        int offset;

        int all_len = strlen(cmd_buffer);
        sscanf(cmd_buffer,"%19s%n",ins,&offset);

        unsigned char matched = 0;
        for(int i = 0; i < sizeof(cmds) / sizeof(struct cmd_t); ++ i)
        {
            if(0 == strcmp(cmds[i].command_name,ins) && all_len > offset)
            {
                cmds[i].command(cmd_buffer+offset);
                matched = 1;
            }
        }
        if(matched == 0)
        {
            printf("unrecongized command: %19s\n",ins);
        }
    }
    return 0;
}




static void cmd_list(const char *args)
{
    // define flags.
    unsigned char show_all_flag = 0;

    // capture args.
    char param[20];
    sscanf(args, "%19s", param);
    int n = strlen(param);
    for(int i = 0; i < n; ++ i)
    {
        if(param[i] == 'a')
        {
            show_all_flag = 1;
        }
    }

    size_t length = duList_length(&employees);
    printf("List of current employees, %u in total.\n", length);
    for(int i = 0; i < length; ++ i)
    {
        employee_t tmp;
        (duList_get(&employees,i,&tmp));
        printf("id:%s name:%s\n", tmp.id, tmp.name);
    }

    length = duList_length(&archivedEmployees);
    if(show_all_flag)
    {
        printf("List of disigned employees, %u in total.\n", length);
        for(int i = 0; i < length; ++ i)
        {
            employee_t tmp;
            (duList_get(&archivedEmployees,i,&tmp));
            printf("(disigned)id:%s name:%s\n", tmp.id, tmp.name);
        }
    }
}

static void cmd_quit(const char * _args)
{
    duList_uninit(&archivedEmployees);
    duList_uninit(&employees);

    running = 0;
}

static void cmd_add(const char * args)
{
    employee_t tmp;
    *tmp.position = '\0';
    
    int nums = sscanf(args,"%19s%255s%511s", tmp.id, tmp.name, tmp.position);
    if(nums < 2)
    {
        printf("add : \"add <id> <name> [discription]\".\n");
        return;
    }

    size_t length = duList_length(&employees);
    for(int i = 0; i < length; ++ i)
    {
        employee_t itr;
        duList_get(&employees, i, &itr);
        if(0==strcmp(tmp.id,(itr.id)))
        {
            printf("duplicate id (same as %s's). not added.\n", itr.name);
            return;
        }
    }

    length = duList_length(&archivedEmployees);
    for(int i = 0; i < length; ++ i)
    {
        employee_t itr;
        duList_get(&archivedEmployees, i, &itr);
        if(0==strcmp(tmp.id,(itr.id)))
        {
            printf("duplicate id (same as %s(resigned)'s). not added.\n", itr.name);
            return;
        }
    }


    duList_insert(&employees, length, &tmp);
}

static void cmd_delete(const char * args)
{
    unsigned char force_delete_flag = 0;

    char id[21];
    char param[21];

    int num = sscanf(args, "%20s%20s", id, param);
    if(num < 1)
    {
        printf("del : \"del <id> [-f(fore delete)]\"\n");
        return;
    }

    if(num == 2)
    {
        int len = strlen(param);
        for(int i = 0; i < len; ++ i)
        {
            if(param[i] == 'f')
            {
                force_delete_flag = 1;
            }
        }
    }

    size_t length = duList_length(&employees);
    for(int i = 0; i < length; ++ i)
    {
        employee_t tmp;
        duList_get(&employees, i, &tmp);
        if(0==strcmp(id,(tmp.id)))
        {
            
            if(force_delete_flag == 0)
            {
                duList_insert(&archivedEmployees,0,&tmp);    
            }

            duList_erase(&employees,i);
            return;
        }
    }

    // find in disigned list, if -f flag is set.
    if(force_delete_flag)
    {
        length = duList_length(&archivedEmployees);
        for(int i = 0; i < length; ++ i)
        {
            employee_t tmp;
            duList_get(&archivedEmployees, i, &tmp);
            if(0==strcmp(id,(tmp.id)))
            {
                duList_erase(&archivedEmployees,i);
                return;
            }
        }
    }
    

    printf("not found.\n");

}

static void cmd_query(const char * args)
{
    char id[20];
    char param[20];

    int num = sscanf(args, "%20s%20s", id, param);
    if(num < 1)
    {
        printf("show : \"show <id>\"\n");
        return;
    }
    

    // find in current_employees list 
    size_t length = duList_length(&employees);
    for(int i = 0; i < length; ++ i)
    {
        employee_t tmp;
        duList_get(&employees, i, &tmp);
        if(0==strcmp(id,(tmp .id)))
        {
            printf("name: %s\ndiscription: %s\n", tmp.name, tmp.position);
            return;
        }
    }

    length =  duList_length(&archivedEmployees);
    for(int i = 0; i < length; ++ i)
    {
        employee_t tmp;
        duList_get(&archivedEmployees, i, &tmp);
        if(0==strcmp(id,(tmp .id)))
        {
            printf("name: %s\ndiscription: %s\n", tmp.name, tmp.position);
            return;
        }
    }

    printf("Not found matching\n");
}

static void cmd_help(const char * _args)
{
    printf(helping);
    return;
}
